package event

import (
	"fmt"
	"log"
	"strconv"
	"sync"

	"github.com/kataras/iris/websocket"

	"im/common"
	"im/dao"
	"im/model"
)

type groupsUsersTable struct {
	mutex   sync.RWMutex
	entries map[int64][]*websocket.NSConn
}

func (ru *groupsUsersTable) GetLen(id int64) int {
	l := 0
	ru.mutex.RLock()
	if _, ok := ru.entries[id]; ok {
		l = len(ru.entries[id])
	}
	ru.mutex.RUnlock()
	return l
}

func (ru *groupsUsersTable) AddConnOfGroup(id int64, conn *websocket.NSConn) bool {

	if !ru.GroupExist(id) {
		return false
	}
	if ru.UserExist(id, conn) {
		return false
	}
	ru.mutex.Lock()
	ru.entries[id] = append(ru.entries[id], conn)
	ru.mutex.Unlock()
	return true
}

func (ru *groupsUsersTable) DelConnOfGroup(id int64, conn *websocket.NSConn) bool {
	if !ru.GroupExist(id) {
		return false
	}
	ru.mutex.Lock()
	defer ru.mutex.Unlock()
	for i, v := range ru.entries[id] {
		if v == conn {
			ru.entries[id] = append(ru.entries[id][:i], ru.entries[id][i+1:]...)
			return true
		}
	}
	return false

}

func (ru *groupsUsersTable) GroupExist(id int64) bool {
	ru.mutex.RLock()
	_, ok := ru.entries[id]
	ru.mutex.RUnlock()
	return ok
}

func (ru *groupsUsersTable) UserExist(id int64, conn *websocket.NSConn) bool {
	if !ru.GroupExist(id) {
		return false
	}
	ru.mutex.RLock()
	defer ru.mutex.RUnlock()
	for _, v := range ru.entries[id] {
		if v == conn {
			return true
		}
	}

	return false
}

var GroupUsersTable groupsUsersTable

func OnGroupJoin() func(*websocket.NSConn, websocket.Message) error {
	return func(nsConn *websocket.NSConn, msg websocket.Message) error {
		var (
			ctx     = websocket.GetContext(nsConn.Conn)
			user    = ctx.Values().Get("user").(model.Users)
			userMsg = model.GroupsMessages{}
			err     = msg.Unmarshal(&userMsg)
			groupId int64
			status  *int8
		)

		groupId, err = strconv.ParseInt(msg.Room, 10, 64)
		if err != nil {
			return err
		}
		status = dao.NewGroupsUsersDao().RelationExist(user.AppsId, groupId, user.Id)
		if status == nil || *status != 1 {
			return common.NewErrorRes(common.ATTRIBUTION_ERROR, "非群聊成员无法加入", userMsg)
		}
		return nil
	}
}

func OnGroupJoined() func(*websocket.NSConn, websocket.Message) error {
	return func(nsConn *websocket.NSConn, msg websocket.Message) error {
		var (
			ctx     = websocket.GetContext(nsConn.Conn)
			user    = ctx.Values().Get("user").(model.Users)
			userMsg = model.GroupsMessages{}
			err     = msg.Unmarshal(&userMsg)
			groupId int64
		)

		groupId, err = strconv.ParseInt(msg.Room, 10, 64)
		if err != nil {
			return err
		}

		//加入房间
		GroupUsersTable.AddConnOfGroup(groupId, nsConn)

		text := fmt.Sprintf("欢迎ID [%d] 的用户 [%s] 加入 [%s] 号房间", user.Id, user.Nickname, msg.Room)
		log.Printf("%s", text)

		// notify others.
		nsConn.Conn.Server().Broadcast(nsConn, websocket.Message{
			Namespace: msg.Namespace,
			Room:      msg.Room,
			Event:     "notify",
			Body:      []byte(text),
		})

		return nil
	}
}

func OnGroupLeft() func(*websocket.NSConn, websocket.Message) error {
	return func(nsConn *websocket.NSConn, msg websocket.Message) error {
		text := fmt.Sprintf("[%s] left from group [%s].", nsConn, msg.Room)
		log.Printf("%s", text)

		groupId, err := strconv.ParseInt(msg.Room, 10, 64)
		if err != nil {
			return err
		}
		GroupUsersTable.DelConnOfGroup(groupId, nsConn)

		// notify others.
		nsConn.Conn.Server().Broadcast(nsConn, websocket.Message{
			Namespace: msg.Namespace,
			Room:     msg.Room,
			Event:     "notify",
			Body:      []byte(text),
		})

		nsConn.Conn.Write(msg)
		return nil
	}
}
